/********************************************************************************
 * @file    hal_wifi.c
 * @brief   wifi通讯
 * 
 * @author  nzttj
 * @date    2025-02-13
 * @version 1.0
 * 
 * Copyright (C) 2025 nzttj
 * 
 * 本软件使用 GNU 通用公共许可证 (GPL) 第 3 版授权。
 * 
 * 您可以自由使用、修改、分发本软件，但必须遵守以下条件：
 * 1. 源代码必须开放，且您修改后的代码也必须以 GPL 许可证发布。
 * 2. 发布或分发本软件时，必须附带本许可证，并提供源代码或获取源代码的方式。
 * 
 * 本软件按“原样”提供，不附带任何担保，使用风险由用户自行承担。
 * 
 ********************************************************************************/

#include "hal_wifi.h"

#include <string.h>

#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"

static const char *TAG = "hal_wifi";
static hal_wifi_event_callback_t hal_wifi_event_callback = NULL;

static void event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data)
{
    hal_wifi_event_t hal_event = HAL_WIFI_EVENT_MAX;

    if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START)
    {
        ESP_LOGI(TAG, "WIFI_EVENT_STA_START");
        hal_event = HAL_WIFI_EVENT_STA_START;
    }
    else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_STOP)
    {
        ESP_LOGI(TAG, "WIFI_EVENT_STA_STOP");
        hal_event = HAL_WIFI_EVENT_STA_STOP;
    }
    else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED)
    {
        hal_event = HAL_WIFI_EVENT_STA_DISCONNECTED;
        wifi_event_sta_disconnected_t *disconnected = (wifi_event_sta_disconnected_t *)event_data;
        ESP_LOGI(TAG, "WIFI disconnect reason : %d", disconnected->reason);
    }
    else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_AP_START)
    {
        ESP_LOGI(TAG, "WIFI_EVENT_AP_START");
        hal_event = HAL_WIFI_EVENT_AP_START;
    }
    else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_AP_STOP)
    {
        ESP_LOGI(TAG, "WIFI_EVENT_AP_STOP");
        hal_event = HAL_WIFI_EVENT_AP_STOP;
    }
    else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_AP_STACONNECTED)
    {
        wifi_event_ap_staconnected_t* event = (wifi_event_ap_staconnected_t*) event_data;
        ESP_LOGI(TAG, "station "MACSTR" join, AID=%d", MAC2STR(event->mac), event->aid);
        hal_event = HAL_WIFI_EVENT_AP_STACONNECTED;
    }
    else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_AP_STADISCONNECTED)
    {
        wifi_event_ap_stadisconnected_t *event = (wifi_event_ap_stadisconnected_t *) event_data;
        ESP_LOGI(TAG, "station "MACSTR" leave, AID=%d", MAC2STR(event->mac), event->aid);
        hal_event = HAL_WIFI_EVENT_AP_STADISCONNECTED;
    }
    else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP)
    {
        ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;
        ESP_LOGI(TAG, "got ip:%s", ip4addr_ntoa(&event->ip_info.ip));
        hal_event = HAL_WIFI_EVENT_STA_GOT_IP;
    }

    // 调用回调函数
    if (hal_wifi_event_callback != NULL)
    {
        hal_wifi_event_callback(hal_event, event_data);
    }
}

int hal_wifi_init(void)
{
    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));
    esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL);
    esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL);
    return 0;
}

int hal_wifi_deinit(void)
{
    return esp_wifi_deinit();
}

int hal_wifi_init_sta(const hal_wifi_sta_cfg_t *sta_config)
{
    wifi_config_t wifi_config = { 0 };

    strncpy((char*)wifi_config.sta.ssid, sta_config->ssid, sizeof(wifi_config.sta.ssid) - 1);
    strncpy((char*)wifi_config.sta.password, sta_config->password, sizeof(wifi_config.sta.password) - 1);

    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
    ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));
    return esp_wifi_start();
}

int hal_wifi_init_ap(const hal_wifi_ap_cfg_t *ap_config)
{
    // 配置 Wi-Fi 为 AP 模式
    wifi_config_t wifi_config = {
        .ap = {
            .ssid = "",
            .ssid_len = strlen(ap_config->ssid),
            .password = "",
            .max_connection = ap_config->max_connections,
            .authmode = WIFI_AUTH_WPA_WPA2_PSK,
            .channel = ap_config->channel,
            .ssid_hidden = 0,   // 不隐藏SSID
        },
    };

    if (wifi_config.ap.ssid_len == 0)
    {
        wifi_config.ap.authmode = WIFI_AUTH_OPEN;
    }
    strncpy((char *)wifi_config.ap.ssid, ap_config->ssid, sizeof(wifi_config.ap.ssid) - 1);
    strncpy((char *)wifi_config.ap.password, ap_config->password, sizeof(wifi_config.ap.password) - 1);

    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));
    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &wifi_config));
    return esp_wifi_start();
}

int hal_wifi_start(void)
{
    return esp_wifi_start();
}

int hal_wifi_stop(void)
{
    return esp_wifi_stop();
}

int hal_wifi_connect(void)
{
    return esp_wifi_connect();
}

int hal_wifi_get_mac(hal_wifi_interface_t ifx, uint8_t *mac)
{
    return esp_wifi_get_mac(ifx, mac);
}

void hal_wifi_register_event_callback(hal_wifi_event_callback_t callback)
{
    hal_wifi_event_callback = callback;
}